import axios from 'axios'
import type { AxiosInstance } from 'axios'
import type { HRequestConfig, InterceptorHooks } from './type'
import { ElMessage } from "element-plus";
import { useUserStore } from '@/store/user'
import Vrouter from '@/router'

// 自定义请求返回数据的类型
interface HData {
  data: object
  code: number
  msg: string
  request_id: string
  timestamp: string
}

class HRequest {
  config: HRequestConfig
  instance: AxiosInstance
  interceptorHooks?: InterceptorHooks

  constructor(options: HRequestConfig) {
    this.config = options
    this.interceptorHooks = options?.interceptorHooks
    this.instance = axios.create(options)
    this.setupInterceptor()
  }

  setupInterceptor(): void {
    this.instance.interceptors.request.use(
      this.interceptorHooks?.requestInterceptor,
      this.interceptorHooks?.requestInterceptorCatch
    )
    this.instance.interceptors.response.use(
      this.interceptorHooks?.responseInterceptor,
      this.interceptorHooks?.responseInterceptorCatch
    )

    this.instance.interceptors.request.use((config) => {
      return config
    })
  }

  // 类型参数的作用，T决定AxiosResponse实例中data的类型
  request<T = any>(config: HRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance
        .request<any, HData>(config)
        .then((res: HData) => {
          // 如果是Blob 类型，说明是下载请求，直接放行
          if (toString.call(res) === '[object Blob]') {
            return resolve(<any>res)
          }
          if (res.code !== 200) {
            // token失效
            if (res.code === 10001) {
              // 非login 页面则需要返回到登录页面
              ElMessage.error(res.msg || '登录过期，请重新登录')
              Vrouter.currentRoute.value.name !== 'login' && useUserStore().logOut()
              reject()
            } else {
              ElMessage.error(res.msg || '很抱歉，请求失败，请稍后重试。')
              reject(res)
            }
          } else {
            resolve(<any>res.data)
          }
        })
        .catch((err) => {
          reject(err)
        })
    })
  }

  get<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({
      ...config,
      params: config.params,
      // params: config.params,
      method: 'GET'
    })
  }

  post<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({
      ...config,
      data: config.data,
      method: 'POST'
    })
  }

  delete<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'DELETE' })
  }

  patch<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'PATCH' })
  }
}

export default HRequest
